#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>//htons
#include <sys/ioctl.h>//ioctl SIOCGIFINDEX
#include <net/if.h>//struct ifreq
#include <netinet/ether.h>//ETH_P_ALL
#include <netpacket/packet.h>
#include <netinet/ip.h>




#include "network_interface.h"
#include "arp_link.h"
#include "ip_pthread.h"
#include "main.h"


extern int interface_num;


int netmask_char_num = 3;

unsigned char arp_data_buf[42]  = {
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // dst MAC	[0]-->[5]
    0, 0, 0, 0, 0, 0, 					// src MAC	[6]-->[11]
    0x08, 0x06,                         // ARP      [12]-->[13]
    0x00, 0x01, 						// Ethernet  [14]-->[15]
	0x08, 0x00, 						// IP  [16]-->[17]
    0x06,								// HW address size	[18]
	0x04,								// protocol(IP here) address size  [19]
    0x00, 0x01, 						// opcode : 1.arp request 2.arp answer 3.rarp request 4.rarp answer  [20]-->[21]
    0, 0, 0, 0, 0, 0, 					// src MAC	[22]-->[27]
    0, 0, 0, 0,							// src ip : 192.168.1.254  [28]-->[31]
    0, 0, 0, 0, 0, 0,					// dst MAC	[32]-->[37]
    0, 0, 0, 0							// dst ip :   [38]-->[41]
};



/******************************************************************
函	数:	void create_arp_msg(unsigned char* p_dst_ip ,int network_num)
功	能: 创建要发送的arp数据报文
参	数: p_dst_ip     network_num 
返回值: void 
*******************************************************************/
void create_arp_msg( unsigned char* p_dst_ip ,int network_num)
{
    // 使用以太网头 修改mac报文头部
    struct ether_header* eth_hdr = (struct ether_header*)arp_data_buf;
    struct ether_arp *arp_hdr = (struct ether_arp *)(arp_data_buf + sizeof(struct ether_header));

    // 修改目的ip为 参数 p_dst_ip
    memcpy( arp_hdr + 24, p_dst_ip, 4 );
    // 修改源 ip
    memcpy( arp_hdr + 14 , net_interfaces[network_num].if_ipaddr, 4 );
    // 修改arp报文的 来源mac
    memcpy(arp_hdr + 8 , net_interfaces[network_num].if_hwaddr , 6 );

    // 修改mac报文中的元mac
    memcpy(eth_hdr->ether_shost , net_interfaces[network_num].if_hwaddr , 6);



}



/******************************************************************
函	数:	int send_msg(char* eth_name ,  char * msg_data , ssize_t data_len)
功	能: 发送数据包
参	数: eth_name 发送段网卡接口    msg_data 
返回值: send_len 发送成功的字节个数 
*******************************************************************/
int send_msg(unsigned  char* eth_name ,  unsigned char * msg_data , ssize_t data_len)
{

    struct ifreq  if_req;
    strncpy( if_req.ifr_name, eth_name , IFNAMSIZ );
    
    if( ioctl( raw_socketfd, SIOCGIFINDEX , &if_req) == -1 )
    {
        perror("ioctl SIOCGIFINDEX");
        exit(-1);
    }

    struct sockaddr_ll sock_ll;
    bzero(&sock_ll, sizeof(sock_ll));
    sock_ll.sll_ifindex = if_req.ifr_ifindex ;

    
    // 发送原始套接字数据
    int send_len = sendto(raw_socketfd, msg_data , data_len , 0 ,(struct sockaddr* )(&sock_ll) , sizeof(sock_ll) );

    return send_len;

}



/******************************************************************
函	数:	void * ip_pthread_handler(void * arg)
功	能: 处理ip线程方法
        根据对应的网段选择发送的网卡
        没有目的ip的mac地址，发送ARP请求

参	数: 
返回值: void 
*******************************************************************/
void * ip_pthread_handler(void * arg)
{
    // 获取传进线程的数据结构体
    RECV_DATA * stru_recv = (RECV_DATA *)arg;

    //  将ip数据包字节数组包装成iphdr
    struct iphdr* ip_hdr = (struct iphdr*)(stru_recv->data + 14);

    
    // 目的ip地址
    // char * p_dst_ip = stru_recv->data + 14 + 16;
    unsigned char* p_dst_ip =  ( unsigned char *)&(ip_hdr->daddr);
    // unsigned char* p_src_ip =  ( unsigned char *)&(ip_hdr->saddr);

    printf("ip_pthread:目的ip-->%d.%d.%d.%d\n", p_dst_ip[0] , p_dst_ip[1] ,p_dst_ip[2] ,p_dst_ip[3]    );
    // printf("ip_pthread:来源ip-->%d.%d.%d.%d\n", p_src_ip[0] , p_src_ip[1] ,p_src_ip[2] ,p_src_ip[3]    );s

    // 查询目的ip地址对应的网卡下标
    int network_num = find_network_segment_bydstip(p_dst_ip);


    // printf("ip_pthread:找到的网段index:%d\n",network_num);

    // 没有找到对应的网段
    if(network_num == get_interface_num())
    {
        printf("can not find this net segment\n");
        return NULL;
    }

    // 广播数据一律不转发
    if( p_dst_ip[3] == 0xff )
    {
        return NULL;
    }

    // 本地回环不转发
    if( strcmp( net_interfaces[network_num].if_name , "lo"  ) == 0 )
    {
        return NULL;
    }

    // 根据ip查找arp链表中 arp节点
    ARP_LINK* p_arp_node = find_arp_byip(arp_head , p_dst_ip);
    
    // 如果没有找到对应的arp的节点
    if( p_arp_node == NULL)
    {
        // 发送arp包， 发送三次，没有找到就放弃转发数据
        int send_times;
        for(send_times = 0; send_times < 5 ; send_times++)
        {
            // 构建好arp报文
            create_arp_msg(p_dst_ip , network_num);
            // 发送arp报文
            int send_len  = send_msg(net_interfaces[network_num].if_name, arp_data_buf , sizeof(arp_data_buf));

            if(send_len < 0)
            {
                perror("send arp");
            }

            // 发送了arp消息之后，如果受到了目的ip的回复，那么路由器中就会接受到arp 回复，即有了arp节点
            p_arp_node = find_arp_byip( arp_head , p_dst_ip);
            // 如果找到了，就退出发送
            if( p_arp_node != NULL)
            {
                break;
            }

        } 

        if( p_arp_node == NULL)
        {
            printf("发送了arp报文之后,还是没有在arp节点中找到对应的目的ip的mac地址\n");
            printf("ip: %d.%d.%d.%d  arp error\n" , p_dst_ip[0], p_dst_ip[1], p_dst_ip[2], p_dst_ip[3] );
            // 结束处理线程
            return NULL;
        }else
        {
            printf("ip: %d.%d.%d.%d  arp ok\n" , p_dst_ip[0], p_dst_ip[1], p_dst_ip[2], p_dst_ip[3]);
        }
    }

    // 转发步骤
    //  1. 以太网头的 目的mac， 替换成查到的目的ip的mac地址
    memcpy( stru_recv->data , net_interfaces[network_num].if_hwaddr , 6);
    //  2. 填上 源mac ， 这个是网卡地址
    memcpy( stru_recv->data + 6 , p_arp_node->mac , 6);

    // 3. 发送消息
    int ret = send_msg(net_interfaces[network_num].if_name, stru_recv->data, stru_recv->data_len );

    if(ret<0){
		printf("msg_data.data_len=%d\n",stru_recv->data_len);
		perror("send ip");
	}

    return NULL;

}